package com.hibase.core.rule.service.ruletableversion.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import cn.hutool.poi.excel.ExcelUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.github.pagehelper.PageInfo;
import com.hibase.common.exception.HibaseAssert;
import com.hibase.common.util.EntityUtil;
import com.hibase.core.mybatis.service.BaseServiceImpl;
import com.hibase.core.redis.util.RedisUtil;
import com.hibase.core.rule.constant.RuleFieldType;
import com.hibase.core.rule.constant.RuleRangeTypeEnum;
import com.hibase.core.rule.constant.RuleStatus;
import com.hibase.core.rule.entity.ruletable.RuleTable;
import com.hibase.core.rule.entity.ruletable.RuleTableData;
import com.hibase.core.rule.entity.ruletable.RuleTableField;
import com.hibase.core.rule.entity.ruletable.query.RuleQueryResultVO;
import com.hibase.core.rule.entity.ruletable.query.RuleTableDataChangeVO;
import com.hibase.core.rule.entity.ruletable.query.TableQuerySearchVO;
import com.hibase.core.rule.entity.ruletable.vo.RuleTableFieldSearchVO;
import com.hibase.core.rule.entity.ruletable.vo.RuleTableFieldViewVO;
import com.hibase.core.rule.entity.ruletable.vo.RuleTableViewVO;
import com.hibase.core.rule.entity.ruletableversion.RuleTableVersion;
import com.hibase.core.rule.entity.ruletableversion.vo.RuleTableVersionSearchVO;
import com.hibase.core.rule.mapper.ruletableversion.RuleTableVersionMapper;
import com.hibase.core.rule.service.ruletable.RuleTableDataService;
import com.hibase.core.rule.service.ruletable.RuleTableFieldService;
import com.hibase.core.rule.service.ruletable.RuleTableQueryService;
import com.hibase.core.rule.service.ruletable.RuleTableService;
import com.hibase.core.rule.service.ruletableversion.RuleTableVersionService;
import com.hibase.core.rule.utils.ExcelHandler;
import com.hibase.core.rule.utils.RuleUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 动态规则表 服务实现类
 * </p>
 *
 * @author zjw
 * @since 2020-10-27
 */
@Slf4j
@Service
@Transactional(rollbackFor = Exception.class)
public class RuleTableVersionServiceImpl extends BaseServiceImpl<RuleTableVersionMapper, RuleTableVersion> implements RuleTableVersionService {

    @Autowired
    RuleTableService ruleTableService;

    @Autowired
    RuleTableFieldService ruleTableFieldService;

    @Autowired
    RuleTableDataService ruleTableDataService;

    @Autowired
    private RedisUtil redisUtil;

    @Autowired
    RuleTableQueryService ruleTableQueryService;

    /**
     * 查询动态规则表列表
     */
    @Override
    public PageInfo<RuleTableVersion> selectRuleTableVersionList(RuleTableVersionSearchVO searchVO) {

        // step 1. 设置查询条件
        QueryWrapper<RuleTableVersion> ruleTableQueryWrapper = new QueryWrapper<>();
        if (StrUtil.isNotBlank(searchVO.getName())) {
            ruleTableQueryWrapper.like("name", searchVO.getName());
        }
        if (StrUtil.isNotBlank(searchVO.getStatus())) {
            ruleTableQueryWrapper.eq("status", searchVO.getStatus());
        }


        PageInfo<RuleTableVersion> page = super.page(searchVO, ruleTableQueryWrapper);
        page.getList().forEach(p -> {
            // step 2. 查询相关表字段和表数据数量
            RuleTable ruleTable = ruleTableService.getById(p.getRuleTableId());
            int fieldCount = ruleTableFieldService.count(new QueryWrapper<RuleTableField>().eq("rule_table_id", ruleTable.getId()));
            int dataCount = ruleTableDataService.count(new QueryWrapper<RuleTableData>().eq("rule_table_version_id", p.getId()));
            p.setFieldCount(String.valueOf(fieldCount));
            p.setDataCount(String.valueOf(dataCount));
            if (RuleStatus.RULE_STATUS_RELEASE.getKey().equals(p.getStatus())) {
                p.setStatus(RuleStatus.RULE_STATUS_RELEASE.getValue());
            } else {
                p.setStatus(RuleStatus.RULE_STATUS_CANCEL.getValue());
            }
        });

        return page;
    }

    /**
     * 改变动态规则表记录
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveRuleTableVersion(RuleTableVersion entity) {
        entity.setStatus(RuleStatus.RULE_STATUS_CANCEL.getKey());
        RuleTableVersion ruleTableVersion=null;
        RuleTable ruleTable=null;
        //前端更新时不传ruletableId了
        if (StrUtil.isNotBlank(entity.getId())) {
            //新增
            ruleTableVersion = super.getById(entity.getId());
            ruleTable = ruleTableService.getById(ruleTableVersion.getRuleTableId());
        }else {
            ruleTable = ruleTableService.getById(entity.getRuleTableId());
        }


        //普通一对一
        SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd");
        //DatePattern.NORM_DATE_PATTERN
        if (!ruleTable.getBeMultiValue() && !ruleTable.getBeFindRange())
            entity.setType(RuleFieldType.NORMAL_ONE.getKey());
        //entity.setName()
        //普通一对多
        if (ruleTable.getBeMultiValue() && !ruleTable.getBeFindRange())
            entity.setType(RuleFieldType.NORMAL_MULT.getKey());
        //范围一对一
        if (!ruleTable.getBeMultiValue() && ruleTable.getBeFindRange())
            entity.setType(RuleFieldType.RANGE_ONE.getKey());
        //范围一对多
        if (ruleTable.getBeFindRange() && ruleTable.getBeFindRange())
            entity.setType(RuleFieldType.RANGE_MULT.getKey());

        super.store(entity);
    }

    /**
     * 查询动态规则表详情
     */
    @Override
    public RuleTableVersion viewRuleTableVersion(String id) {

        RuleTableVersion entity = super.getById(id, true);

        return entity;
    }

    /**
     * 删除动态规则表记录
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteRuleTableVersion(List<String> ids) {
        Collection<RuleTableVersion> ruleTableVersions = super.listByIds(ids);
        for (RuleTableVersion ruleTableVersion : ruleTableVersions) {
            // 状态校验
            HibaseAssert.isTrue(StrUtil.equals(RuleStatus.RULE_STATUS_CANCEL.getKey(),ruleTableVersion.getStatus()),"上线状态不允许操作");
            // 删除数据
            ruleTableDataService.deleteBy(new QueryWrapper<RuleTableData>().eq("rule_table_version_id", ruleTableVersion.getId()));
            // 删除版本表
            super.deleteBy(ruleTableVersion.getId());
        }
    }

    @Override
    public RuleQueryResultVO selectTableData(TableQuerySearchVO searchVO) {
        return null;
    }

    @Override
    public RuleTableViewVO viewRuleTable(String id) {
        // step 1. 获取表基础信息
        RuleTableVersion ruleTableVersion = super.getById(id);
        RuleTable ruleTable = ruleTableService.getById(ruleTableVersion.getRuleTableId(), true);
        int fieldCount = ruleTableFieldService.count(new QueryWrapper<RuleTableField>().eq("rule_table_id", ruleTable.getId()));
        int dataCount = ruleTableDataService.count(new QueryWrapper<RuleTableData>().eq("rule_table_version_id", ruleTableVersion.getId()));
        ruleTableVersion.setFieldCount(String.valueOf(fieldCount));
        ruleTableVersion.setDataCount(String.valueOf(dataCount));

        // step 2. 获取表字段集合
        List<RuleTableField> list = ruleTableFieldService.list(new QueryWrapper<RuleTableField>().eq("rule_table_id", ruleTable.getId()).orderByAsc("column_sort"));

        RuleTableViewVO result = EntityUtil.transform(ruleTableVersion, RuleTableViewVO.class);
        if (CollUtil.isNotEmpty(list)) {
            result.setFieldList(EntityUtil.transform(list, RuleTableFieldViewVO.class));
        }

        return result;
    }

    @Override
    public PageInfo selectRuleTableFieldList(RuleTableFieldSearchVO searchVO) {
        //查询table表
        QueryWrapper<RuleTable> wrapper = new QueryWrapper<>();
        wrapper.eq("name", searchVO.getTableName());
        RuleTable ruleTable = ruleTableService.getOne(wrapper);
        HibaseAssert.notNull(ruleTable, "查询记录为空");

        QueryWrapper<RuleTableField> wrapper1 = new QueryWrapper<>();
        wrapper1.eq("rule_table_id", ruleTable.getId());
        wrapper1.orderByAsc("column_sort");

        return ruleTableFieldService.page(searchVO, wrapper1);
    }

    @Override
    public void exportRuleTableVersion(String id, HttpServletResponse response) {
        //1,通过id查询tableName
        RuleTableVersion tableVersion = super.getById(id);
        RuleTable ruleTable = ruleTableService.getById(tableVersion.getRuleTableId());
        QueryWrapper<RuleTableField> wrapper = new QueryWrapper<>();
        wrapper.eq("rule_table_id", ruleTable.getId());
        wrapper.orderByAsc("column_sort");
        //2,查询到字段集合
        List<RuleTableField> tableFields = ruleTableFieldService.list(wrapper);
        List<String> fields = new ArrayList<>();
        tableFields.forEach(p -> {
            //如果有别名，则导出别名
            if (StrUtil.isNotBlank(p.getFieldAliasName())) {
                fields.add(p.getFieldAliasName());
            } else {
                fields.add(p.getFieldName());
            }
        });
        //
        StringBuilder fileName = new StringBuilder();
        fileName.append(ruleTable.getName());
        fileName.append(".xlsx");

        List<List<String>> data = new ArrayList<>();

        data.add(fields);

        ExcelHandler excelHandler = new ExcelHandler(ExcelHandler.WorkbookVersion.XLSX);
        //给创建一个sheet 并且吧数据写进去  创建一个新的sheet
        excelHandler.write(data, "sheet名称", true);
        //定制一些样式  一般只需要维护表头即可
        excelHandler.setRowStyle(0, 0, excelHandler.makeStyle(ExcelHandler.RowType.HEADER));

        //写入数据后 把数据再写到response即可实现导出了
        excelHandler.flushIntoResponseForDownload(response, fileName.toString());
        //关流
        excelHandler.close();

    }

    /**
     * 批量上线
     *
     * @param ids
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void upLine(List<String> ids) {
        List<RuleTableVersion> versionList = super.listByIds(ids);
        versionList.forEach(version -> {
            HibaseAssert.isFalse(RuleStatus.RULE_STATUS_RELEASE.getKey().equals(version.getStatus()), "不能重复操作!");
            // 校验当前是否再数据库中存在交集
            List<RuleTableVersion> list = super.list(Wrappers.<RuleTableVersion>lambdaQuery()
                    .eq(RuleTableVersion::getStatus, RuleStatus.RULE_STATUS_RELEASE.getKey())
                    .eq(RuleTableVersion::getRuleTableId, version.getRuleTableId())
                    .ne(RuleTableVersion::getId, version.getId())
                    .and(i -> i.between(RuleTableVersion::getStartDate, version.getStartDate(), version.getEndDate())
                            .or().between(RuleTableVersion::getEndDate, version.getStartDate(), version.getEndDate())
                    )
            );
            // todo 过滤掉边界地区
            HibaseAssert.isTrue(CollUtil.isEmpty(list),"{}上线存在交集,请确认启用的开始结束时间",version.getName());
            version.setStatus(RuleStatus.RULE_STATUS_RELEASE.getKey());
            upLine(version);
            super.store(version);
        });
    }

    /**
     * 上线
     *
     * @param version
     */
    public void upLine(RuleTableVersion version) {
        RuleTable table = ruleTableService.getById(version.getRuleTableId(), false);
        HibaseAssert.notNull(table.getBeFindRange(), table.getName() + "范围查找类型不能为空!");
        HibaseAssert.notNull(table.getBeMultiValue(), table.getName() + "多值查找类型不能为空!");
        List<RuleTableData> dataList = ruleTableDataService.list(new QueryWrapper<RuleTableData>()
                .eq("rule_table_version_id", version.getId()));
        HibaseAssert.isTrue(CollUtil.isNotEmpty(dataList), table.getName() + "规则版本表下的数据不能为空!");
        //通过查找项分组
        Map<String, List<RuleTableData>> dataMap = dataList
                .stream()
                .collect(Collectors.groupingBy(RuleTableData::getEavFindData));
        //step 01 得到 场景类型
        //step 02.1 不允许多值 不允许范围 同一查找项 至多有一个结果
        if (Boolean.FALSE.equals(table.getBeFindRange())
                && Boolean.FALSE.equals(table.getBeMultiValue())) {
            initRedisByRuleTableDataNotRangeNotMult(version, table, dataMap);
        }
        //step 02.2 允许多值 不允许范围
        else if (Boolean.FALSE.equals(table.getBeFindRange())
                && Boolean.TRUE.equals(table.getBeMultiValue())) {
            initRedisByRuleTableDataNotRangeCanMult(version, table, dataMap);
        }
        //step 02.3 不允许多值 允许范围 同一查询值 至多有一个结果
        else if (Boolean.TRUE.equals(table.getBeFindRange())
                && Boolean.FALSE.equals(table.getBeMultiValue())) {
            initRedisByRuleTableDataCanRangeNotMult(version, table, dataMap);
        }
        //step 02.4 允许多值 允许范围
        else if (Boolean.TRUE.equals(table.getBeFindRange())
                && Boolean.TRUE.equals(table.getBeMultiValue())) {
            initRedisByRuleTableDataCanRangeCanMult(version, table, dataMap);
        }
    }

    /**
     * 允许多值 允许范围
     *
     * @param version
     * @param table
     * @param dataMap
     */
    private void initRedisByRuleTableDataCanRangeCanMult(RuleTableVersion version, RuleTable table, Map<String, List<RuleTableData>> dataMap) {
        for (Map.Entry<String, List<RuleTableData>> entry : dataMap.entrySet()) {
            List<RuleTableData> value = entry.getValue();
            String key = RuleUtils.getKey(table.getName(), version.getName(),
                    entry.getKey(),
                    value.get(0).getEavFindHash());

            //RScoredSortedSet<Object> sortedSet = redissonClient.getScoredSortedSet(key);
            //通过start+end 进行分组;
            Map<String, List<RuleTableData>> startAndEndMap = value
                    .stream()
                    .collect(Collectors.groupingBy(
                            ruleTableData -> ruleTableData.getEavRangeStartVal() + "and" + ruleTableData.getEavRangeEndVal()
                    ));
            //根据range type 来判断存入
            for (Map.Entry<String, List<RuleTableData>> startAndEnd : startAndEndMap.entrySet()) {
                String startAndEndValue = startAndEnd.getKey();
                List<RuleTableData> data = startAndEnd.getValue();
                BigDecimal startVal = new BigDecimal(startAndEndValue.split("and")[0]);
                BigDecimal endVal = new BigDecimal(startAndEndValue.split("and")[1]);
                List<String> startData = data.stream().map(ruleTableData -> {
                    return JSONUtil.parseObj(ruleTableData.getEavValueData())
                            .putIfAbsent("type", "start").toString();
                }).collect(Collectors.toList());
                List<String> endData = data.stream().map(ruleTableData -> {
                    return JSONUtil.parseObj(ruleTableData.getEavValueData())
                            .putIfAbsent("type", "end").toString();
                }).collect(Collectors.toList());
                if (RuleRangeTypeEnum.LEFT_OR_RIGHT.getKey().equals(table.getRangeType())) {
                    //左合右开
                    // 起 同一乘100 加1
                    startVal = startVal.add(BigDecimal.ONE);
                    startVal = startVal.multiply(BigDecimal.TEN).multiply(BigDecimal.TEN);
                    //sortedSet.add(startVal.doubleValue(), startData);
                    redisUtil.zAdd(key,startData,startVal.doubleValue());
                    // 止
                    endVal = endVal.multiply(BigDecimal.TEN).multiply(BigDecimal.TEN);
                    redisUtil.zAdd(key,CollUtil.newArrayList(endData),endVal.doubleValue());
//                    sortedSet.add(endVal.doubleValue(),
//                            CollUtil.newArrayList(endData));
                } else if (RuleRangeTypeEnum.LEFT_OR_RIGHT_AWAY.getKey().equals(table.getRangeType())) {
                    //左合右开
                    // 起
                    startVal = startVal.multiply(BigDecimal.TEN).multiply(BigDecimal.TEN);
                    redisUtil.zAdd(key,CollUtil.newArrayList(startData),startVal.doubleValue());
//                    sortedSet.add(startVal.doubleValue(),
//                            CollUtil.newArrayList(startData));
                    // 止 同一乘100 减1
                    endVal = endVal.subtract(BigDecimal.ONE);
                    endVal = endVal.multiply(BigDecimal.TEN).multiply(BigDecimal.TEN);
                    redisUtil.zAdd(key,CollUtil.newArrayList(endData),endVal.doubleValue());
//                    sortedSet.add(endVal.doubleValue(),
//                            CollUtil.newArrayList(endData));
                }
            }

        }
    }

    /**
     * 不允许多值 允许范围 同一查询值 至多有一个结果
     *
     * @param version
     * @param table
     * @param dataMap
     */
    private void initRedisByRuleTableDataCanRangeNotMult(RuleTableVersion version, RuleTable table, Map<String, List<RuleTableData>> dataMap) {
        for (Map.Entry<String, List<RuleTableData>> entry : dataMap.entrySet()) {
            List<RuleTableData> value = entry.getValue();
            String key = RuleUtils.getKey(table.getName(), version.getName(),
                    entry.getKey(),
                    value.get(0).getEavFindHash());
            //RScoredSortedSet<Object> sortedSet = redissonClient.getScoredSortedSet(key);
            //根据range type 来判断存入
            value.forEach(data -> {
                BigDecimal startVal = data.getEavRangeStartVal();
                BigDecimal endVal = data.getEavRangeEndVal();
                String startJson = JSONUtil.parseObj(data.getEavValueData())
                        .putIfAbsent("type", "start").toString();
                String endJson = JSONUtil.parseObj(data.getEavValueData())
                        .putIfAbsent("type", "end").toString();
                if (RuleRangeTypeEnum.LEFT_OR_RIGHT.getKey().equals(table.getRangeType())) {
                    //左合右开
                    // 起 同加一 乘100
                    startVal = startVal.add(BigDecimal.ONE);
                    startVal = startVal.multiply(BigDecimal.TEN).multiply(BigDecimal.TEN);
                    redisUtil.zAdd(key,CollUtil.newArrayList(startJson),startVal.doubleValue());
//                    sortedSet.add(startVal.doubleValue(),
//                            CollUtil.newArrayList(startJson));
                    // 止
                    endVal = endVal.multiply(BigDecimal.TEN).multiply(BigDecimal.TEN);
                    redisUtil.zAdd(key,CollUtil.newArrayList(endJson),endVal.doubleValue());
//                    sortedSet.add(endVal.doubleValue(),
//                            CollUtil.newArrayList(endJson));
                } else if (RuleRangeTypeEnum.LEFT_OR_RIGHT_AWAY.getKey().equals(table.getRangeType())) {
                    //左合右开
                    // 起
                    startVal = startVal.multiply(BigDecimal.TEN).multiply(BigDecimal.TEN);
                    redisUtil.zAdd(key,CollUtil.newArrayList(startJson),startVal.doubleValue());
//                    sortedSet.add(startVal.doubleValue(),
//                            CollUtil.newArrayList(startJson));
                    // 止 同一减1乘100
                    endVal = endVal.subtract(BigDecimal.ONE);
                    endVal = endVal.multiply(BigDecimal.TEN).multiply(BigDecimal.TEN);
                    redisUtil.zAdd(key,CollUtil.newArrayList(endJson),endVal.doubleValue());
//                    sortedSet.add(endVal.doubleValue(),
//                            CollUtil.newArrayList(endJson));
                }
            });

        }
    }

    /**
     * 允许多值 不允许范围
     *
     * @param version
     * @param table
     * @param dataMap
     */
    private void initRedisByRuleTableDataNotRangeCanMult(RuleTableVersion version, RuleTable table, Map<String, List<RuleTableData>> dataMap) {
        for (Map.Entry<String, List<RuleTableData>> entry : dataMap.entrySet()) {
            // 允许多值 不允许范围
            List<RuleTableData> value = entry.getValue();
            String key = RuleUtils.getKey(table.getName(), version.getName(),
                    entry.getKey(),
                    value.get(0).getEavFindHash());
//            RList<Object> rList = redissonClient.getList(key);
//            rList.clear();
//            rList.addAll(value.stream()
//                    .map(RuleTableData::getEavValueData)
//                    .collect(Collectors.toList()));
            redisUtil.delete(key);
            redisUtil.lLeftPushAll(key,value.stream()
                    .map(RuleTableData::getEavValueData)
                    .collect(Collectors.toList()));
        }
    }

    /**
     * 不允许多值 不允许范围 同一查找项 至多有一个结果
     *
     * @param version
     * @param table
     * @param dataMap
     */
    private void initRedisByRuleTableDataNotRangeNotMult(RuleTableVersion version, RuleTable table, Map<String, List<RuleTableData>> dataMap) {
        for (Map.Entry<String, List<RuleTableData>> entry : dataMap.entrySet()) {
            // 不允许多值 不允许范围 同一查找项 至多有一个结果
            List<RuleTableData> value = entry.getValue();
            HibaseAssert.isTrue(value.size() <= 1, version.getName() + "不允许多值不允许范围同一查找项,至多有一个结果!" + "value: " + value.get(0).getEavFindData());
            String key = RuleUtils.getKey(table.getName(), version.getName(),
                    entry.getKey(),
                    value.get(0).getEavFindHash());
            //step 03 将data放入redis
//            RList<Object> rList = redissonClient.getList(key);
//            rList.clear();
//            rList.add(value.get(0).getEavValueData());
            redisUtil.delete(key);
            redisUtil.lLeftPushAll(key,value.get(0).getEavValueData());
        }
    }

    private void initRedisByRuleTableData(RuleTableVersion version, RuleTable table, List<RuleTableData> dataList, Map<String, List<RuleTableData>> dataMap) {
        if (CollUtil.isNotEmpty(dataList)) {
            for (Map.Entry<String, List<RuleTableData>> entry : dataMap.entrySet()) {
                //step 02 更加不同的场景生成不同的key  表名.版本名.hash
                if (Boolean.FALSE.equals(table.getBeFindRange())
                        && Boolean.FALSE.equals(table.getBeMultiValue())) {
                    // 不允许多值 不允许范围 同一查找项 至多有一个结果
                    HibaseAssert.isTrue(entry.getValue().size() <= 1, "不允许多值不允许范围同一查找项,至多有一个结果!");
                    List<RuleTableData> value = entry.getValue();
                    String key = RuleUtils.getKey(table.getName(), version.getName(),
                            entry.getKey(),
                            entry.getValue().get(0).getEavFindHash());
                    //step 03 将data放入redis
//                    RList<Object> rList = redissonClient.getList(key);
//                    rList.add(value.stream()
//                            .map(RuleTableData::getEavValueData)
//                            .collect(Collectors.toList()));
                    redisUtil.lLeftPushAll(key,value.stream()
                            .map(RuleTableData::getEavValueData)
                            .collect(Collectors.toList()));
                } else if (Boolean.TRUE.equals(table.getBeFindRange())
                        && Boolean.FALSE.equals(table.getBeMultiValue())) {
                    // 允许多值 不允许范围
                    List<RuleTableData> value = entry.getValue();
                    String key = RuleUtils.getKey(table.getName(), version.getName(),
                            entry.getKey(),
                            value.get(0).getEavFindHash());
//                    RList<Object> rList = redissonClient.getList(key);
//                    rList.add(value.stream()
//                            .map(RuleTableData::getEavValueData)
//                            .collect(Collectors.toList()));
                    redisUtil.lLeftPushAll(key,value.stream()
                            .map(RuleTableData::getEavValueData)
                            .collect(Collectors.toList()));
                } else if (Boolean.FALSE.equals(table.getBeFindRange())
                        && Boolean.TRUE.equals(table.getBeMultiValue())) {
                    // 不允许多值 允许范围 同一查询值 至多有一个结果
                    HibaseAssert.isTrue(entry.getValue().size() <= 1, "允许多值不允许范围同一查找项,至多有一个结果!");
                    List<RuleTableData> value = entry.getValue();
                    String key = RuleUtils.getKey(table.getName(), version.getName(),
                            entry.getKey(),
                            entry.getValue().get(0).getEavFindHash());
                    //RScoredSortedSet<Object> sortedSet = redissonClient.getScoredSortedSet(key);
                    //根据range type 来判断存入
                    BigDecimal startVal = entry.getValue().get(0).getEavRangeStartVal();
                    BigDecimal endVal = entry.getValue().get(0).getEavRangeEndVal();
                    if (RuleRangeTypeEnum.LEFT_OR_RIGHT.getKey().equals(table.getRangeType())) {
                        //左合右开
                        // 起 同一乘100 加1
                        startVal = startVal.multiply(BigDecimal.TEN);
                        startVal = startVal.add(BigDecimal.ONE);
                        redisUtil.zAdd(key,value.stream()
                                .map(RuleTableData::getEavValueData)
                                .collect(Collectors.toList()),startVal.doubleValue());
//                        sortedSet.add(startVal.doubleValue(),
//                                value.stream()
//                                        .map(RuleTableData::getEavValueData)
//                                        .collect(Collectors.toList()));
                        // 止
                        redisUtil.zAdd(key,value.stream()
                                .map(RuleTableData::getEavValueData)
                                .collect(Collectors.toList()),endVal.doubleValue());
//                        sortedSet.add(endVal.doubleValue(),
//                                value.stream()
//                                        .map(RuleTableData::getEavValueData)
//                                        .collect(Collectors.toList()));
                    } else if (RuleRangeTypeEnum.LEFT_OR_RIGHT_AWAY.getKey().equals(table.getRangeType())) {
                        //左合右开
                        // 起
                        redisUtil.zAdd(key,value.stream()
                                .map(RuleTableData::getEavValueData)
                                .collect(Collectors.toList()),
                                startVal.doubleValue());
//                        sortedSet.add(startVal.doubleValue(),
//                                value.stream()
//                                        .map(RuleTableData::getEavValueData)
//                                        .collect(Collectors.toList()));
                        // 止 同一乘100 减1
                        endVal = endVal.multiply(BigDecimal.TEN);
                        endVal = endVal.subtract(BigDecimal.ONE);
                        redisUtil.zAdd(key,value.stream()
                                .map(RuleTableData::getEavValueData)
                                .collect(Collectors.toList()),
                                endVal.doubleValue());
//                        sortedSet.add(endVal.doubleValue(),
//                                value.stream()
//                                        .map(RuleTableData::getEavValueData)
//                                        .collect(Collectors.toList()));
                    }
                } else if (Boolean.TRUE.equals(table.getBeFindRange())
                        && Boolean.TRUE.equals(table.getBeMultiValue())) {
                    List<RuleTableData> value = entry.getValue();
                    String key = RuleUtils.getKey(table.getName(), version.getName(),
                            entry.getKey(),
                            entry.getValue().get(0).getEavFindHash());
                    //RScoredSortedSet<Object> sortedSet = redissonClient.getScoredSortedSet(key);
                    //根据range type 来判断存入
                    BigDecimal startVal = entry.getValue().get(0).getEavRangeStartVal();
                    BigDecimal endVal = entry.getValue().get(0).getEavRangeEndVal();
                    if (RuleRangeTypeEnum.LEFT_OR_RIGHT.getKey().equals(table.getRangeType())) {
                        //左合右开
                        // 起 同一乘100 加1
                        startVal = startVal.multiply(BigDecimal.TEN);
                        startVal = startVal.add(BigDecimal.ONE);
                        redisUtil.zAdd(key,value.stream()
                                .map(RuleTableData::getEavValueData)
                                .collect(Collectors.toList()),
                                startVal.doubleValue());
//                        sortedSet.add(startVal.doubleValue(),
//                                value.stream()
//                                        .map(RuleTableData::getEavValueData)
//                                        .collect(Collectors.toList()));
                        // 止
                        redisUtil.zAdd(key,value.stream()
                                .map(RuleTableData::getEavValueData)
                                .collect(Collectors.toList()),
                                endVal.doubleValue());
//                        sortedSet.add(endVal.doubleValue(),
//                                value.stream()
//                                        .map(RuleTableData::getEavValueData)
//                                        .collect(Collectors.toList()));
                    } else if (RuleRangeTypeEnum.LEFT_OR_RIGHT_AWAY.getKey().equals(table.getRangeType())) {
                        //左合右开
                        // 起
                        redisUtil.zAdd(key,value.stream()
                                .map(RuleTableData::getEavValueData)
                                .collect(Collectors.toList()),
                                startVal.doubleValue());
//                        sortedSet.add(startVal.doubleValue(),
//                                value.stream()
//                                        .map(RuleTableData::getEavValueData)
//                                        .collect(Collectors.toList()));
                        // 止 同一乘100 减1
                        endVal = endVal.multiply(BigDecimal.TEN);
                        endVal = endVal.subtract(BigDecimal.ONE);
                        redisUtil.zAdd(key,value.stream()
                                .map(RuleTableData::getEavValueData)
                                .collect(Collectors.toList()),
                                endVal.doubleValue());
//                        sortedSet.add(endVal.doubleValue(),
//                                value.stream()
//                                        .map(RuleTableData::getEavValueData)
//                                        .collect(Collectors.toList()));
                    }
                }
            }
        }
    }

    /**
     * 下线
     *
     * @param ids
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void downLine(List<String> ids) {
        List<RuleTableVersion> versionList = (List<RuleTableVersion>) super.listByIds(ids);
        versionList.forEach(version -> {
            HibaseAssert.isFalse(RuleStatus.RULE_STATUS_CANCEL.getKey().equals(version.getStatus()), "不能重复操作!");
            version.setStatus(RuleStatus.RULE_STATUS_CANCEL.getKey());
            downLine(version);
        });
        //step 01 更加不同的场景生成不同的key
        super.storeBatch(versionList);
        //step 02 清除redis中的数据
    }

    /**
     * 下线
     *
     * @param version
     */
    public void downLine(RuleTableVersion version) {
        //step 01 更加不同的场景生成不同的key
        RuleTable table = ruleTableService.getById(version.getRuleTableId());
        HibaseAssert.notNull(table.getBeFindRange(), "范围查找类型不能为空!");
        HibaseAssert.notNull(table.getBeMultiValue(), "多值查找类型不能为空!");
        List<RuleTableData> dataList = ruleTableDataService.list(new QueryWrapper<RuleTableData>()
                .eq("rule_table_version_id", version.getId()));
        Map<String, List<RuleTableData>> dataMap = dataList
                .stream()
                .collect(Collectors.groupingBy(RuleTableData::getEavFindData));
        //step 02 清除redis中的数据
        for (Map.Entry<String, List<RuleTableData>> entry : dataMap.entrySet()) {
            List<RuleTableData> value = entry.getValue();
            String key = entry.getKey();
            String redisKey = RuleUtils.getKey(table.getName(), version.getName(),
                    key, value.get(0).getEavFindHash());
            if ((Boolean.FALSE.equals(table.getBeFindRange())
                    && Boolean.TRUE.equals(table.getBeMultiValue()))
                    ||
                    (Boolean.TRUE.equals(table.getBeFindRange())
                            && Boolean.TRUE.equals(table.getBeMultiValue()))
            ) {
//                RScoredSortedSet<Object> sortedSet = redissonClient.getScoredSortedSet(redisKey);
//                sortedSet.clear();
                redisUtil.delete(key);
            } else {
                redisUtil.delete(redisKey);
//                RList<Object> rList = redissonClient.getList(redisKey);
//                rList.clear();
            }
        }
    }

    /**
     * 导入动态表数据
     * 构造RuleTableDataChangeVO,复用 changeData
     *
     * @param inputStream
     * @param id
     */
    @Override
    public void importRuletableVersion(InputStream inputStream, String id) {

        cn.hutool.poi.excel.ExcelReader reader = ExcelUtil.getReader(inputStream);
        List<List<Object>> read = reader.read();

        List<Object> field = read.get(0);

        List<Object> data = new ArrayList<>();
        for (int i = 0; i < read.size(); i++) {
            List<Object> row = read.get(i);
            //过滤excel中的首行
            if (i == 0) {
                continue;
            }
            //读取每一行的数据，put 到map中，key 字段名称 value 字段的值
            Map<String, String> map = new LinkedHashMap<>();
            for (int j = 0; j < row.size(); j++) {
                if (row.get(j) instanceof Long) {
                    map.put((String) field.get(j), Long.toString((Long) row.get(j)));
                } else if (row.get(j) instanceof Double) {
                    map.put((String) field.get(j), String.valueOf(row.get(j)));
                } else
                    map.put((String) field.get(j), (String) row.get(j));
            }
            data.add(map);
        }

        RuleTableVersion ruleTable = super.getById(id);
        //将整个excel表逐行写入数据库
        data.forEach(p -> {
            RuleTableDataChangeVO entity = new RuleTableDataChangeVO();
            //entity.setId(ruleTable.getId());
            entity.setDataList((Map<String, String>) p);
            entity.setRuleTableVersionId(id);
            entity.setTableName(ruleTable.getName());
            //将一行数据写入数据库
            ruleTableQueryService.changeData(entity);
        });

    }

    @Override
    public void exportRuleTableVersionData(String id, HttpServletResponse response) {

        RuleTableVersion tableVersion = super.getById(id);

        TableQuerySearchVO vo = new TableQuerySearchVO();
        vo.setRuleTableVersionId(tableVersion.getId());
        vo.setPageSize(100000);
        RuleQueryResultVO ruleQueryResultVO = ruleTableQueryService.selectTableData(vo);
        Map<String, String> fieldMap = new LinkedHashMap<>();
        List<String> fieldList = new ArrayList<>();
        List<RuleTableField> fieldEntityList = ruleQueryResultVO.getFieldList();

        fieldEntityList.forEach(p -> {
            if (StrUtil.isNotBlank(p.getFieldAliasName())) {
                fieldList.add(p.getFieldAliasName());
                fieldMap.put(p.getFieldName(),p.getFieldAliasName());
            } else {
                fieldList.add(p.getFieldName());
                fieldMap.put(p.getFieldName(),p.getFieldAliasName());
            }
        });

        StringBuilder fileName = new StringBuilder();
        fileName.append(tableVersion.getName());
        fileName.append(".xlsx");

        List<List<String>> data = new ArrayList<>();

        //表头
        data.add(fieldList);

        //1，拼接json字符串，转map,
        //2, 遍历map，将value组成list
        List<RuleTableData> list = ruleTableDataService.list(new QueryWrapper<RuleTableData>().eq("rule_table_version_id", tableVersion.getId()).orderByAsc("row_sort"));
        for (RuleTableData entity : list) {

            Map findData = JSONObject.parseObject(entity.getEavFindData(), LinkedHashMap.class);

            Map valData = (Map) JSONObject.parseObject(entity.getEavValueData(), LinkedHashMap.class);

            findData.putAll(valData);

            LinkedHashMap sortFindDate = new LinkedHashMap();
            //排序
            for (Map.Entry<String, String> fieldEntity : fieldMap.entrySet()){
                if (findData.containsKey(fieldEntity.getKey())) {
                    sortFindDate.put(StrUtil.isNotBlank(fieldEntity.getValue())?fieldEntity.getValue():fieldEntity.getKey(),findData.get(fieldEntity.getKey()));
                }
            }
//            for (String field : fieldList) {
//                if (findData.containsKey(field)) {
//                    sortFindDate.put(field,findData.get(field));
//                }
//            }

            //将排序好的一行数据写入excel对象中
            List val = new LinkedList();
            for (Object value : sortFindDate.values()) {
                val.add(value);
            }
            data.add(val);

        }

        //data.add(ruleQueryResultVO.getDataPage().getList());

        ExcelHandler excelHandler = new ExcelHandler(ExcelHandler.WorkbookVersion.XLSX);
        //给创建一个sheet 并且吧数据写进去  创建一个新的sheet
        excelHandler.write(data, "sheet名称", true);
        //定制一些样式  一般只需要维护表头即可
        excelHandler.setRowStyle(0, 0, excelHandler.makeStyle(ExcelHandler.RowType.HEADER));

        //写入数据后 把数据再写到response即可实现导出了
        excelHandler.flushIntoResponseForDownload(response, fileName.toString());
        //关流
        excelHandler.close();

    }

    @Override
    public void deleteTableData(String id) {

        ruleTableDataService.deleteBy(new QueryWrapper<RuleTableData>().eq("rule_table_version_id", id));

    }
}
